from basics import models as basics_models
from basics.serializers import CasesSerializers
from ApiTest import models as api_models
from ApiTest import serializers as api_serializers
from ProjectTool.ApiTool.parsing_data import ParsingData
from WEBTest import models as web_models
from ProjectTool.WebTool.ParsingStepsWebData import ParsingStepsWebData
from ProjectTool.common_tool.data_tool.file_uploaded import FileUploaded
from ProjectTool.common_tool.data_tool.get_query_dict import GetQueryDict
from ProjectTool.common_tool.data_tool.save_sql_detail import SaveSqlDetail
from ProjectTool.common_tool.in_out_parameter import FuncParameter,StepsData
from utils.base_response import BaseResponse
import datetime
import json


class ExecuteCasesTool:

    def __init__(self, cases_ids, driver_status=None):
        self.cases_ids = cases_ids
        self.driver_status = driver_status  # 是否使用无界面浏览器 True:使用   False：不使用
        self.cases_query_set = None  # 用例数据
        self.cases_detail_querys = {}  # 用例与步骤数据
        self.detail_objs = [
            (api_models.ApiDetail, self.execute_api_detail),  # 接口明细步骤
            (web_models.Steps, self.execute_web_detail),  # 接口明细步骤
        ]

    # 用例数据初始化
    def get_cases_query_set(self):
        query_set = basics_models.Cases.objects.filter(id__in=self.cases_ids, status=1)
        if query_set.count():
            query_set.update(test_status=3)
            self.cases_query_set = query_set.order_by('project_id', 'module_id', 'id')

    # 用例步骤初始化
    def get_cases_detail_query_set(self):
        for cases_query in self.cases_query_set:
            # 获取步骤
            cases_detail_query = cases_query.casesdetail_set.filter(status=1).order_by('sort')
            if cases_detail_query.count():
                cases_detail_query.update(test_status=3, results=3)
                for detail_query in cases_detail_query:
                    content_object = detail_query.content_object
                    content_object.results = 3
                    content_object.save()
                self.cases_detail_querys[cases_query] = cases_detail_query

    # 接口明细步骤
    def execute_api_detail(self, queryset, steps_data, data_warehouse, driver=None):
        '''
        执行接口测试，分发处
        :param queryset: 步骤实现的queryset
        :param data_warehouse: 数据仓库
        :return:
        '''
        obj = ParsingData(
            serializer=api_serializers.ApiDetailSerializers,
            queryset=queryset,
            data_warehouse=data_warehouse,
            steps_data=steps_data
        )
        obj.run()
        res = obj.res
        data_warehouse = obj.data_warehouse  # 数据仓库
        return res, data_warehouse, driver

    # WEB明细步骤
    def execute_web_detail(self, queryset, steps_data, data_warehouse, driver=None):
        '''
        执行接口测试，分发处
        :param queryset: 步骤实现的queryset
        :param data_warehouse: 数据仓库
        :return:
        '''
        obj = ParsingStepsWebData(
            queryset=queryset,
            steps_data=steps_data,
            driver=driver,
            driver_status=self.driver_status,
            data_warehouse=data_warehouse
        )
        obj.run()
        res = obj.res
        driver = obj.driver
        return res, data_warehouse, driver

    # 数据处理
    def get_parsing_data(self, out_data, data_warehouse):
        res = BaseResponse()
        if out_data:
            func_obj = FuncParameter(out_data)
            func_obj.run()
            out_data = func_obj.obj_data
            if func_obj.res.status:
                res = func_obj.res
            if not res.status:
                try:
                    out_data = json.loads(out_data) if out_data else {}
                except Exception as e:
                    res.status = 1
                    res.msg = '数据转行字典失败！'
                    res.error = str(e.args)
            if not res.status:
                out_obj = StepsData(out_data, data_warehouse, None)
                out_obj.run()
                out_data = out_obj.out_data
                if out_obj.res.status:
                    res = out_obj.res
        return out_data, res

    # 以用例为key步骤为value
    def steps_distribute(self, detail_query, data_warehouse=None, driver=None):
        # 步骤分发
        queryset = detail_query.content_object
        steps_data_template = detail_query.steps_data_template
        steps_data, res = self.get_parsing_data(steps_data_template, data_warehouse)
        results = None
        status = False
        if not res.status:
            for detail in self.detail_objs:
                if isinstance(queryset, detail[0]):
                    func = detail[1]
                    func_res, data_warehouse, driver = func(queryset, steps_data, data_warehouse, driver)
                    if func_res.status:
                        res = func_res
                    status = True
                    break
        if status:
            results = queryset.results
        else:
            res.status = 1
            res.msg = '获取失败'
            res.data = None

        return res, data_warehouse, driver, results,steps_data

    # 执行用例
    def execute_cases(self):
        res_data = {
            'cases_sum': 0,  # 用例总条数
            'cases_execute_sum': 0,  # 用例执行条数
            'cases_failure_sum': 0,  # 用例失败条数
            'cases_not_execute_sum': 0,  # 用例未执行条数
            'cases_failure_ids': [],  # 用例失败id列表
            'cases_detail_sum': 0,  # 明细总条数
            'cases_detail_execute_sum': 0,  # 明细执行条数
            'cases_detail_failure_sum': 0,  # 明细失败条数
            'cases_detail_not_execute_sum': 0,  # 明细未执行条数
            'cases_detail_failure_ids': [],  # 明细失败id列表
        }
        res_data['cases_sum'] = res_data['cases_sum'] + len(self.cases_detail_querys)
        for cases_query in self.cases_detail_querys:  # 遍历用例，此处条件成熟时可考虑实现并发
            res_data['cases_execute_sum'] = res_data['cases_execute_sum'] + 1
            data_warehouse = {}
            cases_test_status = 1
            driver = None
            cases_detail_lis = self.cases_detail_querys[cases_query]  # 获取用例下的步骤
            res_data['cases_detail_sum'] = res_data['cases_detail_sum'] + len(cases_detail_lis)
            for cases_detail in cases_detail_lis:  # 遍历步骤
                res_data['cases_detail_execute_sum'] = res_data['cases_detail_execute_sum'] + 1
                res, data_warehouse, driver, results, steps_data = self.steps_distribute(cases_detail, data_warehouse, driver=driver)  # 步骤分发
                results = results if results else 3
                if results == cases_detail.assert_status:
                    test_status = 1
                else:
                    test_status = 2
                cases_detail.results = results
                cases_detail.test_status = test_status
                cases_detail.steps_data = steps_data
                cases_detail.error_info = json.dumps(res.dict,ensure_ascii=False) if res.status else None
                cases_detail.save()
                if test_status != 1:  # 判断是否执行成功，若失败则终止，剩余的步骤不会执行
                    if cases_test_status != 2:
                        res_data['cases_failure_sum'] = res_data['cases_failure_sum'] + 1
                        res_data['cases_failure_ids'].append(cases_query.id)
                        cases_test_status = 2
                    res_data['cases_detail_failure_sum'] = res_data['cases_detail_failure_sum'] + 1
                    res_data['cases_detail_failure_ids'].append(cases_detail.id)
                    # break
            if driver:
                driver.quit()
            query_dict = GetQueryDict().get_query()
            file_name = ''.join([
                'warehouse_data',
                '_%s_' % cases_query.id,
                datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S'),
                '.txt'])
            obj = FileUploaded(data_warehouse,file_name).get_uploaded_file()
            query_dict.__setitem__('warehouse_data', obj)  # 数据仓库写入
            query_dict.__setitem__('test_status', cases_test_status)  # 用例的测试结果
            res_dict = SaveSqlDetail(CasesSerializers, cases_query, query_dict).save()  # 主要保存数据仓库数据
        res_data['cases_not_execute_sum'] = res_data['cases_sum'] - res_data['cases_execute_sum']
        res_data['cases_detail_not_execute_sum'] = res_data['cases_detail_sum'] - res_data['cases_detail_execute_sum']

        return res_data

    def run(self):
        self.get_cases_query_set()
        self.get_cases_detail_query_set()
        res_data = self.execute_cases()
        return res_data
